package routing

import (
	"net/http"
	"strings"
)

type (
	FilterFunc func() bool
	Action     func(http.ResponseWriter, *http.Request) string
)

/**
 * 路由结构
 */
type Rtr struct {
	routes map[string][]*Route
	byes   map[string]Action
	groups []Grp
	verbs  []string
	static []string
	strict bool
}

/**
 * 路由动词
 */
var verbs = []string{"GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "HEAD"}

/**
 * 返回路由对象
 * @return *Rtr
 */
func Router() *Rtr {
	return new(Rtr)
}

/**
 * 注册路由
 * @param verb   string
 * @param path   string
 * @param action Action
 * @return *Route
 */
func (rt *Rtr) register(verb string, path string, action Action) *Route {

	verb = strings.ToUpper(verb)

	if false == Whether(verb) {
		throwInvalidVerb(verb)
	}

	if nil == rt.routes {
		rt.routes = make(map[string][]*Route)
	}

	if nil == rt.routes[verb] {
		rt.routes[verb] = []*Route{}
	}

	if "/" != path {
		path = strings.TrimRight(path, "/")
	}

	_route := &Route{path: path, action: action}

	rt.routes[verb] = append(rt.routes[verb], _route)

	if 0 < rt.groupSize() {
		rt.group(_route)
	}

	return _route
}

/**
 * 注册路由对象
 * @param verb string
 * @param route *Route
 */
func (rt *Rtr) registerRoute(verb string, route *Route) {

	verb = strings.ToUpper(verb)

	if false == Whether(verb) {
		throwInvalidVerb(verb)
	}

	rt.routes[verb] = append(rt.routes[verb], route)
}

/**
 * 注册多组路由
 * @param verbs string
 * @param path string
 * @param action Action
 * @return *Route
 */
func (rt *Rtr) Any(verbs string, path string, action Action) *Route {

	var r *Route

	for _, _verb := range strings.Split(strings.Trim(verbs, "|"), "|") {
		if nil == r {
			r = rt.register(_verb, path, action)
		} else {
			rt.registerRoute(_verb, r)
		}
	}

	return r
}

/**
 * 注册GET路由
 * @param path string
 * @param action Action
 * @return *Route
 */
func (rt *Rtr) Get(path string, action Action) *Route {
	return rt.register("GET", path, action)
}

/**
 * 注册POST路由
 * @param path string
 * @param action Action
 * @return *Route
 */
func (rt *Rtr) Post(path string, action Action) *Route {
	return rt.register("POST", path, action)
}

/**
 * 注册PUT路由
 * @param path string
 * @param action Action
 * @return *Route
 */
func (rt *Rtr) Put(path string, action Action) *Route {
	return rt.register("PUT", path, action)
}

/**
 * 注册PATCH路由
 * @param path string
 * @param action Action
 * @return *Route
 */
func (rt *Rtr) Patch(path string, action Action) *Route {
	return rt.register("PATCH", path, action)
}

/**
 * 注册DELETE路由
 * @param path string
 * @param action Action
 * @return *Route
 */
func (rt *Rtr) Delete(path string, action Action) *Route {
	return rt.register("DELETE", path, action)
}

/**
 * 注册OPTIONS路由
 * @param path string
 * @param action Action
 * @return *Route
 */
func (rt *Rtr) Options(path string, action Action) *Route {
	return rt.register("OPTIONS", path, action)
}

/**
 * 注册HEAD路由
 * @param path string
 * @param action Action
 * @return *Route
 */
func (rt *Rtr) Head(path string, action Action) *Route {
	return rt.register("HEAD", path, action)
}

/**
 * 注册404路由
 * @param empty action
 * @param verb string
 */
func (rt *Rtr) Bye(empty Action, verb string) {

	if nil == rt.byes {
		rt.byes = make(map[string]Action)
	}

	if "" == verb {
		for _, verb := range rt.verbs {
			rt.byes[verb] = empty
		}
	} else {
		if false == Whether(verb) {
			throwInvalidVerb(verb)
		}

		rt.byes[strings.ToUpper(verb)] = empty
	}
}

/**
 * 注册资源路由
 * @param path string
 */
func (rt *Rtr) Static(path string) {

	if nil == rt.static {
		rt.static = []string{}
	}

	rt.static = append(rt.static, path)
}

/**
 * 匹配是否区分大小写
 * @param strict bool
 */
func (rt *Rtr) Strict(strict bool) {
	rt.strict = strict
}

/**
 * 返回指定动词路由长度
 * @param verb string
 * @return int
 */
func (rt *Rtr) GetSize(verb string) int {

	if false == Whether(verb) {
		throwInvalidVerb(verb)
	}

	return len(rt.routes[verb])
}

/**
 * 返回注册的路由
 * @return map[string][]*Route
 */
func (rt *Rtr) GetRoutes() map[string][]*Route {
	return rt.routes
}

/**
 * 返回注册的404路由
 * @return map[string]action
 */
func (rt *Rtr) GetByes() map[string]Action {
	return rt.byes
}

/**
 * 返回指定404路由
 * @param verb string
 * @return action
 */
func (rt *Rtr) getBye(verb string) Action {

	if _bye, _ok := rt.byes[verb]; _ok {
		return _bye
	}

	return nil
}

/**
 * 判断动词是否有效
 * @param verb string
 * @return bool
 */
func Whether(verb string) bool {

	if "" != verb {
		for _, _v := range Verbs() {
			if _v == strings.ToUpper(verb) {
				return true
			}
		}
	}

	return false
}

/**
 * 返回路由动词
 * @return []string
 */
func Verbs() []string {
	return verbs
}
